package com.chat.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chat.business.common.thread_local.UserIdThreadLocal;
import com.chat.business.mapper.MessageChannelMappingMapper;
import com.chat.business.service.IGroupService;
import com.chat.business.service.IMessageChannelMappingService;
import com.chat.business.service.IUserService;
import com.chat.business.utils.RedisHashUtil;
import com.chat.common.dto.GetGroupDTO;
import com.chat.common.entity.Group;
import com.chat.common.entity.MessageChannelMapping;
import com.chat.common.entity.User;
import com.chat.common.enums.NoticeType;
import com.chat.common.form.ListForm;
import com.chat.common.utils.DtoVoUtil;
import com.chat.common.vo.*;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author weikjie
 * @since 2024-03-29
 */
@Service
public class MessageChannelMappingServiceImpl extends ServiceImpl<MessageChannelMappingMapper, MessageChannelMapping> implements IMessageChannelMappingService {

    @Resource
    private IUserService userService;
    @Lazy
    @Resource
    private IGroupService groupService;
    @Resource
    private RedisHashUtil redisHashUtil;

    /**
     * 查询这个用户的所有“好友”关系，并处理成“好友列表“返回
     * <p>
     * SELECT id,from_id,to_id,is_group,is_active FROM t_message_channel_mapping WHERE (is_group = ? AND from_id = ?)
     * <p>
     * SELECT id,account,username,password,age,sex,email,phone,creation_time,update_time,avatar
     * FROM t_user
     * WHERE id IN ( friendIds )
     *
     * @return
     */
    @Override
    public R<List<UserVo>> getAllFriends() {
        Long userId = UserIdThreadLocal.get();
        LambdaQueryWrapper<MessageChannelMapping> channelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        channelLambdaQueryWrapper
                .eq(MessageChannelMapping::getIsGroup, false)//频道不是群聊
                .eq(MessageChannelMapping::getFromId, userId);//这个用户所在的所有频道
        //处理数据得到所有的好友id
        List<Long> friendIds = list(channelLambdaQueryWrapper).stream()
                .map(channelMapping -> {
                    if (channelMapping.getFromId().equals(userId))
                        return channelMapping.getToId();
                    else
                        return channelMapping.getFromId();
                }).collect(Collectors.toList());
        if (friendIds.size() == 0) {//没有好友
            return R.succeed(new ArrayList<UserVo>());
        }
        //根据好友id，查询好友，并处理成VO（好友列表）返回
        List<UserVo> friendList = userService.listByIds(friendIds).stream()
                .map(user -> DtoVoUtil.entityToDtoOrVo(user, UserVo.class))
                .collect(Collectors.toList());
        return R.succeed(friendList);
    }


    /**
     * 删除映射表的中好友映射
     * 并更新Redis中的频道映射，A删除B，A和B在Redis中的映射都更新
     * 要注意的是B也是在线时，Redis中才有B的频道映射缓存，不然只更新MySQL中的就可以
     * <p>
     * SELECT id,account,username,password,age,sex,email,phone,creation_time,update_time,avatar FROM t_user WHERE (account = ?)
     * <p>
     * DELETE FROM t_message_channel_mapping WHERE (is_group = ? AND (from_id = ? AND to_id = ? OR from_id = ? AND to_id = ?))
     *
     * @param userAccount
     * @return
     */
    @Override
    public R removeFriend(String userAccount) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getAccount, userAccount);
        User toRemoveFriend = userService.getOne(userLambdaQueryWrapper);
        Long userId = UserIdThreadLocal.get();
        Long toRemoveFriendId = toRemoveFriend.getId();
//        Long toRemoveFriendId = 2L;//测试用
        LambdaQueryWrapper<MessageChannelMapping> channelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        channelLambdaQueryWrapper
                .eq(MessageChannelMapping::getIsGroup, false)//频道不是群聊
                .and(wq -> wq//查询（自己，好友）或（好友，自己）的频道映射
                        .eq(MessageChannelMapping::getFromId, toRemoveFriendId)
                        .eq(MessageChannelMapping::getToId, userId)
                        .or()
                        .eq(MessageChannelMapping::getFromId, userId)
                        .eq(MessageChannelMapping::getToId, toRemoveFriendId)
                );
        remove(channelLambdaQueryWrapper);
        return R.succeed();
    }

    /**
     * 添加好友关系
     *
     * @param fromId
     * @param toId
     * @return
     */
    @Override
    public R addFriendMessageChannelMapping(Long fromId, Long toId) {
        MessageChannelMapping messageChannelMapping = new MessageChannelMapping();
        messageChannelMapping.setFromId(fromId);
        messageChannelMapping.setToId(toId);
        messageChannelMapping.setIsGroup(false);
        messageChannelMapping.setIsActive(true);
        save(messageChannelMapping);//A-》B
        MessageChannelMapping messageChannelMapping2 = new MessageChannelMapping();
        messageChannelMapping2.setFromId(toId);
        messageChannelMapping2.setToId(fromId);
        messageChannelMapping2.setIsGroup(false);
        messageChannelMapping2.setIsActive(true);
        save(messageChannelMapping2);//B-》A
        return R.succeed();
    }

    /**
     * 加入群
     *
     * @param fromId
     * @param toId
     * @return
     */
    @Override
    public R addGroupMessageChannelMapping(Long fromId, Long toId) {
        MessageChannelMapping messageChannelMapping = new MessageChannelMapping();
        messageChannelMapping.setFromId(fromId);
        messageChannelMapping.setToId(toId);
        messageChannelMapping.setIsGroup(true);
        messageChannelMapping.setIsActive(true);
        save(messageChannelMapping);//user-》group
        return R.succeed();
    }

    /**
     * 退出群
     *
     * @param groupId
     * @return
     */
    @Override
    public R quitGroup(Long groupId) {
        LambdaQueryWrapper<MessageChannelMapping> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(MessageChannelMapping::getFromId, UserIdThreadLocal.get())
                .eq(MessageChannelMapping::getToId, groupId)
                .eq(MessageChannelMapping::getIsGroup, true);
        remove(lambdaQueryWrapper);//删除消息频道中的记录
        //TODO：给每个群成员发送有人群群通知，以便他们更新本地群数据
        //查询所有群成员id
        List<Long> groupMemberIds = getGroupMemberIds(groupId);
        //构建通知体
        Map<String, Object> map = NoticeVO.NoticeDataBuilder
                .builder()
                .put("quitGroupUserId", UserIdThreadLocal.get())
                .put("groupId", groupId)
                .build();
        groupMemberIds.forEach(id -> {
            //发送通知
            redisHashUtil.publishNotice(NoticeVO.builder().data(map)
                    .date(new Date())
                    .consumerId(id)
                    .publishId(groupId)
                    .noticeType(NoticeType.groupUserOut)
                    .build());
        });
        return R.succeed("已退出该群聊");
    }

    /**
     * 获取这个群的所有成员id（从消息频道表中）
     * <p>
     * 这个方法要做缓存
     *
     * @param groupId
     * @return
     */
    @Override
    public List<Long> getGroupMemberIds(Long groupId) {
        //查询群成员消息频道
        LambdaQueryWrapper<MessageChannelMapping> messageChannelMappingLambdaQueryWrapper = new LambdaQueryWrapper<>();
        messageChannelMappingLambdaQueryWrapper.eq(MessageChannelMapping::getIsGroup, true)
                .eq(MessageChannelMapping::getToId, groupId);
        List<MessageChannelMapping> groupMemberMessageChannelMappings = list(messageChannelMappingLambdaQueryWrapper);
        //处理MessageChannelMapping，得到群的所有成员id
        return groupMemberMessageChannelMappings.stream().map(MessageChannelMapping::getFromId).collect(Collectors.toList());
    }

    /**
     * 根据群号（群id）查询这个群的所有成员信息
     * <p>
     * 这个方法要做缓存
     *
     * @param groupId
     * @return
     */
    @Override
    public R<List<UserVo>> getGroupMembers(Long groupId) {
        List<Long> groupMemberIds = getGroupMemberIds(groupId);
        List<User> users = userService.listByIds(groupMemberIds);
        List<UserVo> userVos = users.stream()
                .map(user -> DtoVoUtil.entityToDtoOrVo(user, UserVo.class))
                .collect(Collectors.toList());
        return R.succeed(userVos);
    }

    /**
     * 根据关键词：
     * 查询
     *
     * @param keyword
     * @return
     */
    @Override
    public R<List<SearchChannelMappingVO>> searchChannelMapping(String keyword) {
        List<User> userList = userService.findByKeyword(keyword);//查询相关用户
        List<Group> groupList = groupService.findByKeyword(keyword);//查询相关群
        //处理好友查询结果
        List<SearchChannelMappingVO> collect = userList.stream().map(user ->
                SearchChannelMappingVO.builder()
                        .headImage(user.getAvatar())
                        .isGroup(false)
                        .userAccountOrGroupAccount(user.getAccount())
                        .usernameOrGroupName(user.getUsername())
                        .id(user.getId()).build()
        ).collect(Collectors.toList());
        //处理群聊查询结果
        List<SearchChannelMappingVO> collect1 = groupList.stream().map(group -> SearchChannelMappingVO.builder()
                .headImage(group.getGroupAvatar())
                .isGroup(true)
                .userAccountOrGroupAccount(group.getGroupAccount())
                .usernameOrGroupName(group.getGroupName())
                .id(group.getId()).build()
        ).collect(Collectors.toList());
        collect.addAll(collect1);//将群聊的查询结果拼接在好友的查询结果后面
        return R.succeed(collect);
    }

    /**
     * 根据账号查询用户
     *
     * @param account
     * @return
     */
    @Override
    public R<UserVo> getFriendByAccount(String account) {
        User one = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getAccount, account));
        if (one == null) return R.failed("没有这个用户");
        UserVo userVo = DtoVoUtil.entityToDtoOrVo(one, UserVo.class);
        return R.succeed(userVo);
    }

    /**
     * 查找用户的所有群
     *
     * @param userId
     * @return
     */
    @Override
    public R<List<GroupVO>> getUserGroups(Long userId) {
        LambdaQueryWrapper<MessageChannelMapping> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(MessageChannelMapping::getFromId, userId).eq(MessageChannelMapping::getIsGroup, true);
        List<MessageChannelMapping> list = list(lambdaQueryWrapper);//这个用户的全部群的消息频道
        //群id
        List<Long> groupIds = list.stream().map(MessageChannelMapping::getToId).collect(Collectors.toList());
        if (groupIds.size() == 0) return R.succeed();
        //查出群的具体信息
        List<GroupVO> groupVOS = groupService.listByIds(groupIds).stream()
                .map(it -> {
                    GroupVO groupVO = DtoVoUtil.entityToDtoOrVo(it, GroupVO.class);
                    groupVO.setGroupMsgGetLastTimeMilli(0L);
                    User user = userService.getById(it.getGroupLeaderId());
                    groupVO.setGroupLeaderAccount(user.getAccount());
                    return groupVO;
                })
                .collect(Collectors.toList());
        return R.succeed(groupVOS);
    }
}
